package com.lhh.apst.library;

import com.lhh.apst.library.utils.TypedAttrUtils;
import ohos.agp.components.*;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;
import ohos.utils.PlainArray;

import java.io.IOException;

/**
 * Created by linhomhom on 2015/9/22.
 */
public class CustomPagerSlidingTabStrip extends ScrollView implements Component.DrawTask, Component.EstimateSizeListener {
    private DirectionalLayout.LayoutConfig expandedTabLayoutParams;

    private final PageListener pageListener = new PageListener();

    /**
     * PageSlider页面切换监听
     */
    public PageSlider.PageChangedListener delegatePageListener;

    private DirectionalLayout tabsContainer;
    private PageSlider pager;

    private int tabCount;

    private int currentPosition = 0;

    private Paint rectPaint;
    private Paint dividerPaint;

    private boolean checkedTabWidths = false;

    private int indicatorColor = 0xFF666666;
    private int underlineColor = 0x1A000000;
    private int dividerColor = 0x1A000000;

    private boolean shouldExpand = true;

    private int scrollOffset = 52;
    private int indicatorHeight = 10;
    private int underlineHeight = 10;
    private int dividerPadding = 12;
    private int tabPadding = 24;
    private int tabPaddingTopBottom = 0;
    private int dividerWidth = 1;

    private int lastScrollX = 0;

    private OnTabClickListener mOnTabClickListener;

    /**
     * Tab点击接口
     *
     * @since 2021-04-30
     */
    public interface OnTabClickListener {
        /**
         * 点击方法
         *
         * @param pos 点击位置
         */
        void onClick(int pos);
    }

    /**
     * CustomTabProvider
     *
     * @since 2021-04-30
     */
    public interface CustomTabProvider {
        /**
         * 获取选中tabView
         *
         * @param position    选中位置
         * @param convertView Component
         * @return Component
         */
        Component getSelectTabView(int position, Component convertView);

        /**
         * 获取未选中tabView
         *
         * @param position    选中位置
         * @param convertView Component
         * @return Component
         */
        Component getDisSelectTabView(int position, Component convertView);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet AttrSet
     */
    public CustomPagerSlidingTabStrip(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    /**
     * 构造函数
     *
     * @param context   上下文
     * @param attrSet   AttrSet
     * @param styleName String
     */
    public CustomPagerSlidingTabStrip(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        setMatchViewportEnabled(true);

        tabsContainer = new DirectionalLayout(context);
        tabsContainer.setOrientation(DirectionalLayout.HORIZONTAL);
        LayoutConfig layoutConfig = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_PARENT);
        tabsContainer.setLayoutConfig(layoutConfig);
        addComponent(tabsContainer);

        indicatorColor = TypedAttrUtils.getIntColor(attrSet, "apTabIndicatorColor", indicatorColor);
        underlineColor = TypedAttrUtils.getIntColor(attrSet, "apTabUnderlineColor", underlineColor);
        dividerColor = TypedAttrUtils.getIntColor(attrSet, "apTabDividerColor", dividerColor);
        indicatorHeight = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabIndicatorHeight", indicatorHeight);
        underlineHeight = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabUnderlineHeight", underlineHeight);
        dividerPadding = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabDividerPadding", dividerPadding);
        tabPadding = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabPaddingLeftRight", tabPadding);
        tabPaddingTopBottom = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabPaddingTopBottom", tabPaddingTopBottom);
        shouldExpand = TypedAttrUtils.getBoolean(attrSet, "apTabShouldExpand", shouldExpand);
        scrollOffset = TypedAttrUtils.getDimensionPixelSize(attrSet, "apTabScrollOffset", scrollOffset);

        rectPaint = new Paint();
        rectPaint.setAntiAlias(true);
        rectPaint.setStyle(Paint.Style.FILL_STYLE);

        dividerPaint = new Paint();
        dividerPaint.setAntiAlias(true);
        dividerPaint.setStrokeWidth(dividerWidth);

        expandedTabLayoutParams = new DirectionalLayout.LayoutConfig(0, LayoutConfig.MATCH_PARENT, TableLayout.Alignment.ALIGNMENT_FILL, 1.0f);

        if (mDisSelectTabViewCache == null) {
            mDisSelectTabViewCache = new PlainArray<>();
        }
        if (mSelectTabViewCache == null) {
            mSelectTabViewCache = new PlainArray<>();
        }

        addDrawTask(this);
        setEstimateSizeListener(this);
    }

    public void setOnTabClickListener(OnTabClickListener onTabClickListener) {
        mOnTabClickListener = onTabClickListener;
    }

    /**
     * 设置PageSlider
     *
     * @param pager PageSlider
     */
    public void setViewPager(PageSlider pager) {
        this.pager = pager;

        if (pager.getProvider() == null) {
            throw new IllegalStateException("PageSlider does not have Provider instance.");
        }

        pager.addPageChangedListener(pageListener);

        notifyDataSetChanged();
    }

    public void setOnPageChangeListener(PageSlider.PageChangedListener listener) {
        this.delegatePageListener = listener;
    }

    /**
     * 更新数据
     */
    public void notifyDataSetChanged() {
        tabsContainer.removeAllComponents();
        tabCount = pager.getProvider().getCount();

        for (int i = 0; i < tabCount; i++) {
            if (pager.getProvider() instanceof CustomTabProvider) {
                Component view = ((CustomTabProvider) pager.getProvider()).getSelectTabView(i, null);
                setSelectTabView(i, view);
                updateViewStyle(view);
                addTab(i, view);
            }
        }

        checkedTabWidths = false;
        pageListener.onPageChosen(0);
    }

    private PageOnClickListener mPageOnClickListener;

    /**
     * PageOnClickListener
     *
     * @since 2021-04-30
     */
    class PageOnClickListener implements ClickedListener {
        @Override
        public void onClick(Component component) {
            int tag = (int) component.getTag();
            if (mOnTabClickListener != null) {
                mOnTabClickListener.onClick(tag);
            }
            scrollToChild(tag, 0);
            pager.setCurrentPage(tag);
        }
    }

    private void addTab(final int position, Component view) {
        if (mPageOnClickListener == null) {
            mPageOnClickListener = new PageOnClickListener();
        }
        view.setTag(position);
        view.setClickedListener(mPageOnClickListener);
        tabsContainer.addComponent(view, position);
    }

    /**
     * 获取tab Component
     *
     * @param pos 选中位置
     * @return Component
     */
    public Component getTabAt(int pos) {
        if (pos >= tabsContainer.getChildCount()) {
            throw new IllegalStateException("pos is too big.");
        }
        return tabsContainer.getComponentAt(pos);
    }

    private void updateTabStyles() {
        for (int i = 0; i < tabCount; i++) {
            Component v = tabsContainer.getComponentAt(i);
            updateViewStyle(v);
        }
    }

    /**
     * 更新view样式
     *
     * @param v Component
     */
    public void updateViewStyle(Component v) {
        v.setLayoutConfig(expandedTabLayoutParams);
        if (shouldExpand) {
            v.setPadding(0, 0, 0, 0);
        } else {
            v.setPadding(tabPadding, tabPaddingTopBottom, tabPadding, tabPaddingTopBottom);
        }
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        if (!shouldExpand || EstimateSpec.getMode(widthMeasureSpec) == EstimateSpec.UNCONSTRAINT) {
            return false;
        }

        if (tabsContainer.getChildCount() == 0) {
            return false;
        }

        int myWidth = getEstimatedWidth();
        int childWidth = 0;
        for (int i = 0; i < tabCount; i++) {
            childWidth += tabsContainer.getComponentAt(i).getEstimatedWidth();
        }

        if (!checkedTabWidths && childWidth > 0 && myWidth > 0) {
            if (childWidth <= myWidth) {
                for (int i = 0; i < tabCount; i++) {
                    tabsContainer.getComponentAt(i).setLayoutConfig(expandedTabLayoutParams);
                }
            }
            checkedTabWidths = true;
        }

        return true;
    }

    private void scrollToChild(int position, int offset) {
        if (tabCount == 0) {
            return;
        }

        int newScrollX = tabsContainer.getComponentAt(position).getLeft() + offset;

        if (position > 0 || offset > 0) {
            newScrollX -= scrollOffset;
        }

        if (newScrollX != lastScrollX) {
            lastScrollX = newScrollX;
            scrollTo(newScrollX, 0);
        }
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (tabCount == 0) {
            return;
        }
        drawTabNormalMode(canvas);
    }

    private void drawTabNormalMode(Canvas canvas) {
        final int height = getHeight();

        // 设置提示下划线的颜色
        rectPaint.setColor(new Color(indicatorColor));

        // default: line below current tab
        Component currentTab = tabsContainer.getComponentAt(currentPosition);
        if (currentTab == null) {
            return;
        }
        float lineLeft = currentTab.getLeft();
        float lineRight = currentTab.getRight();

        //绘制提示下划线
        canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);

        // 绘制下划线
        rectPaint.setColor(new Color(underlineColor));
        canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);

        // 绘制分割线
        dividerPaint.setColor(new Color(dividerColor));

        for (int i = 0; i < tabCount - 1; i++) {
            Component tab = tabsContainer.getComponentAt(i);
            canvas.drawLine(tab.getRight(), dividerPadding, tab.getRight(), height - dividerPadding, dividerPaint);
        }
    }

    /**
     * PageListener
     *
     * @since 2021-04-30
     */
    private class PageListener implements PageSlider.PageChangedListener {
        @Override
        public void onPageSliding(int position, float positionOffset, int positionOffsetPixels) {
            scrollToChild(position, (int) (positionOffset * tabsContainer.getComponentAt(position).getWidth()));
            invalidate();

            if (delegatePageListener != null) {
                delegatePageListener.onPageSliding(position, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageSlideStateChanged(int state) {
            if (state == PageSlider.SLIDING_STATE_IDLE) {
                scrollToChild(pager.getCurrentPage(), 0);
            }

            if (delegatePageListener != null) {
                delegatePageListener.onPageSlideStateChanged(state);
            }
        }

        @Override
        public void onPageChosen(int position) {
            setSelectItem(position);
            if (delegatePageListener != null) {
                delegatePageListener.onPageChosen(position);
            }
            currentPosition = position;
            invalidate();
        }
    }

    private PlainArray<Component> mDisSelectTabViewCache;

    private Component getDisSelectTabView(int position) {
        return mDisSelectTabViewCache.get(position).get();
    }

    private void setDisSelectTabView(int position, Component view) {
        mDisSelectTabViewCache.put(position, view);
    }

    private PlainArray<Component> mSelectTabViewCache;

    private Component getSelectTabView(int position) {
        return mSelectTabViewCache.get(position).get();
    }

    private void setSelectTabView(int position, Component view) {
        mSelectTabViewCache.put(position, view);
    }

    /**
     * 设置选中item
     *
     * @param position 当前位置
     */
    public void setSelectItem(int position) {
        if (!(pager.getProvider() instanceof CustomTabProvider)) {
            return;
        }

        for (int i = 0; i < tabsContainer.getChildCount(); i++) {
            tabsContainer.removeComponentAt(i);

            Component view;

            if (i == position) {
                view = ((CustomTabProvider) pager.getProvider()).getSelectTabView(i, null);
                setSelectTabView(i, view);
            } else {
                view = ((CustomTabProvider) pager.getProvider()).getDisSelectTabView(i, null);
                setDisSelectTabView(i, view);
            }

            view.setTag(i);

            if (mPageOnClickListener == null) {
                mPageOnClickListener = new PageOnClickListener();
            }

            view.setClickedListener(mPageOnClickListener);

            tabsContainer.addComponent(view, i);

            updateViewStyle(view);
        }
    }

    /**
     * 设置下标颜色值
     *
     * @param indicatorColor 下标颜色值
     */
    public void setIndicatorColor(int indicatorColor) {
        this.indicatorColor = indicatorColor;
        invalidate();
    }

    /**
     * 设置下标颜色值
     *
     * @param resId 下标颜色值资源id
     */
    public void setIndicatorColorResource(int resId) {
        try {
            this.indicatorColor = getResourceManager().getElement(resId).getColor();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.fillInStackTrace();
        }
        invalidate();
    }

    public int getIndicatorColor() {
        return this.indicatorColor;
    }

    /**
     * 设置下标线高度
     *
     * @param indicatorLineHeightPx 下标线高度
     */
    public void setIndicatorHeight(int indicatorLineHeightPx) {
        this.indicatorHeight = indicatorLineHeightPx;
        invalidate();
    }

    public int getIndicatorHeight() {
        return indicatorHeight;
    }

    /**
     * 设置下边线颜色值
     *
     * @param underlineColor 下边线颜色值
     */
    public void setUnderlineColor(int underlineColor) {
        this.underlineColor = underlineColor;
        invalidate();
    }

    /**
     * 设置下边线颜色值
     *
     * @param resId 资源id
     */
    public void setUnderlineColorResource(int resId) {
        try {
            this.underlineColor = getResourceManager().getElement(resId).getColor();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.fillInStackTrace();
        }
        invalidate();
    }

    public int getUnderlineColor() {
        return underlineColor;
    }

    /**
     * 设置分割线颜色值
     *
     * @param dividerColor 资源id
     */
    public void setDividerColor(int dividerColor) {
        this.dividerColor = dividerColor;
        invalidate();
    }

    /**
     * 设置分割线颜色值
     *
     * @param resId 资源id
     */
    public void setDividerColorResource(int resId) {
        try {
            this.dividerColor = getResourceManager().getElement(resId).getColor();
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.fillInStackTrace();
        }
        invalidate();
    }

    public int getDividerColor() {
        return dividerColor;
    }

    /**
     * 设置下标线高度
     *
     * @param underlineHeightPx 下标线高度
     */
    public void setUnderlineHeight(int underlineHeightPx) {
        this.underlineHeight = underlineHeightPx;
        invalidate();
    }

    public int getUnderlineHeight() {
        return underlineHeight;
    }

    /**
     * 设置分割线padding
     *
     * @param dividerPaddingPx 分割线padding
     */
    public void setDividerPadding(int dividerPaddingPx) {
        this.dividerPadding = dividerPaddingPx;
        invalidate();
    }

    public int getDividerPadding() {
        return dividerPadding;
    }

    /**
     * 设置滚动偏移量
     *
     * @param scrollOffsetPx 滚动偏移量
     */
    public void setScrollOffset(int scrollOffsetPx) {
        this.scrollOffset = scrollOffsetPx;
        invalidate();
    }

    public int getScrollOffset() {
        return scrollOffset;
    }

    /**
     * 是否展开
     *
     * @param shouldExpand 是否展开
     */
    public void setShouldExpand(boolean shouldExpand) {
        this.shouldExpand = shouldExpand;
        postLayout();
    }

    public boolean getShouldExpand() {
        return shouldExpand;
    }

    /**
     * tab左右padding
     *
     * @param paddingPx 左右padding值
     */
    public void setTabPaddingLeftRight(int paddingPx) {
        this.tabPadding = paddingPx;
        updateTabStyles();
    }

    public int getTabPaddingLeftRight() {
        return tabPadding;
    }
}
